﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Caca.MineSweeper.AI;

namespace Caca.MineSweeper.Win
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
        }

        Game game;
        Grid grid;
        Player player;

        public bool IsAutoOpenZeroSurroundsPlot { get; set; }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            InitGameAndPlayer();

            IsAutoOpenZeroSurroundsPlot = false;

            grid = BuildGameGrid(game);
            main.Children.Add(grid);
        }

        private void InitGameAndPlayer()
        {
            var stringField = new string[] 
            { 
                "OOOOX",
                "XOOOO",
                "OOOXO",
                "OXOOO",
                "OOOOX",
                "OOXOO",
            };

            //var field = MineFieldGenerator.Generate(20, 10, 20);
            var field = MineFieldGenerator.Generate(stringField);

            game = new Game(field);
            player = new Player(game);
            player.OnMark += new MarkEventHandler(player_OnMark);
            player.OnUnCover += new UnCoverEventHandler(player_OnUnCover);
        }

        #region AI

        void player_OnUnCover(int x, int y)
        {
            Open(x, y);
        }

        void player_OnMark(int x, int y)
        {
            SwithMark(x, y);
        }

        #endregion

        private Grid BuildGameGrid(Game g)
        {
            Grid result = new Grid();
            PlotDataTemplateSelector dtSelector = new PlotDataTemplateSelector();

            for (int i = 0; i < g.FieldHeight; i++)
                result.RowDefinitions.Add(new RowDefinition());

            for (int i = 0; i < g.FieldWidth; i++)
                result.ColumnDefinitions.Add(new ColumnDefinition());

            for (int x = 0; x < g.FieldWidth; x++)
                for (int y = 0; y < g.FieldHeight; y++)
                {
                    ContentControl c = new ContentControl();
                    c.SetValue(Grid.RowProperty, y);
                    c.SetValue(Grid.ColumnProperty, x);
                    c.ContentTemplateSelector = dtSelector;
                    c.Content = g.GetPlot(x, y);

                    result.Children.Add(c);
                }

            return result;
        }

        private void Window_Button_Click(object sender, RoutedEventArgs e)
        {
            var b = e.OriginalSource as Button;
            var c = e.Source as ContentControl;

            if (b != null && c != null)
            {
                if (b.Tag is CoveredPlot)
                {
                    Open(c);
                }
            }
        }

        #region Private

        private Plot Open(int x, int y)
        {
            var plot = game.UnCover(x, y);

            var c = GetControlInPosition(x, y);
            c.Content = plot;

            if (IsAutoOpenZeroSurroundsPlot)
                AutoOpenSurroundIfSurroundMinesIsZero(x, y, plot);

            return plot;
        }

        private void OpenSurround(int x, int y)
        {
            int[,] surround = {
                                  {-1, -1},
                                  {0, -1},
                                  {1, -1},
                                  {-1, 0},
                                  {1, 0},
                                  {-1, 1},
                                  {0, 1},
                                  {1, 1},
                              };
            for (int i = 0; i < 8; i++)
            {
                var tempx = x + surround[i, 0];
                var tempy = y + surround[i, 1];
                if (!ValidPosition(tempx, tempy))
                    continue;

                if (game.GetPlot(tempx, tempy) is CoveredPlot)
                    Open(tempx, tempy);
            }
        }

        private Plot Open(ContentControl c)
        {
            int x;
            int y;
            GetControlPosition(c, out x, out y);

            var plot = game.UnCover(x, y);
            c.Content = plot;

            if (IsAutoOpenZeroSurroundsPlot)
                AutoOpenSurroundIfSurroundMinesIsZero(x, y, plot);
            return plot;
        }

        private void AutoOpenSurroundIfSurroundMinesIsZero(int x, int y, Plot plot)
        {
            var p = plot as NonMinePlot;
            if (p == null || p.SurroundMines != 0)
                return;

            OpenSurround(x, y);
        }

        private void OpenSurround(ContentControl c)
        {
            int x;
            int y;
            GetControlPosition(c, out x, out y);

            OpenSurround(x, y);
        }

        private ContentControl GetControlInPosition(int x, int y)
        {
            return grid.Children.Cast<ContentControl>().First(
                c => (int)c.GetValue(Grid.RowProperty) == y
                && (int)c.GetValue(Grid.ColumnProperty) == x
                );
        }

        private bool ValidPosition(int x, int y)
        {
            return x >= 0 && y >= 0 && x < game.FieldWidth && y < game.FieldHeight;
        }

        private static void GetControlPosition(ContentControl c, out int x, out int y)
        {
            x = (int)c.GetValue(Grid.ColumnProperty);
            y = (int)c.GetValue(Grid.RowProperty);
        }

        private void SwithMark(int x, int y)
        {
            var c = GetControlInPosition(x, y);
            if (c.Content is CoveredPlot)
            {
                c.Content = game.Mark(x, y);
            }
            else if (c.Content is MarkedPlot)
            {
                c.Content = game.UnMark(x, y);
            }
        }

        private void SwithMark(ContentControl c)
        {
            int x;
            int y;
            GetControlPosition(c, out x, out y);

            if (c.Content is CoveredPlot)
            {
                c.Content = game.Mark(x, y);
            }
            else if (c.Content is MarkedPlot)
            {
                c.Content = game.UnMark(x, y);
            }
        }

        #endregion

        #region mouse event

        private void Window_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            var c = e.Source as ContentControl;
            if (c != null && e.LeftButton != MouseButtonState.Pressed)
            {
                SwithMark(c);
            }
        }

        private void Window_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            var c = e.Source as ContentControl;
            if (c != null && c.IsMouseOver)
                if (e.LeftButton == MouseButtonState.Pressed && e.RightButton == MouseButtonState.Released)
                {
                    OpenSurround(c);
                }
        }

        #endregion

        private void NextMove_Click(object sender, RoutedEventArgs e)
        {
            player.NextMove();
        }
    }
}
